const WIDTH_TBL = [
  '212222',
  '222122',
  '222221',
  '121223',
  '121322',
  '131222',
  '122213',
  '122312',
  '132212',
  '221213',
  '221312',
  '231212',
  '112232',
  '122132',
  '122231',
  '113222',
  '123122',
  '123221',
  '223211',
  '221132',
  '221231',
  '213212',
  '223112',
  '312131',
  '311222',
  '321122',
  '321221',
  '312212',
  '322112',
  '322211',
  '212123',
  '212321',
  '232121',
  '111323',
  '131123',
  '131321',
  '112313',
  '132113',
  '132311',
  '211313',
  '231113',
  '231311',
  '112133',
  '112331',
  '132131',
  '113123',
  '113321',
  '133121',
  '313121',
  '211331',
  '231131',
  '213113',
  '213311',
  '213131',
  '311123',
  '311321',
  '331121',
  '312113',
  '312311',
  '332111',
  '314111',
  '221411',
  '431111',
  '111224',
  '111422',
  '121124',
  '121421',
  '141122',
  '141221',
  '112214',
  '112412',
  '122114',
  '122411',
  '142112',
  '142211',
  '241211',
  '221114',
  '413111',
  '241112',
  '134111',
  '111242',
  '121142',
  '121241',
  '114212',
  '124112',
  '124211',
  '411212',
  '421112',
  '421211',
  '212141',
  '214121',
  '412121',
  '111143',
  '111341',
  '131141',
  '114113',
  '114311',
  '411113',
  '411311',
  '113141',
  '114131',
  '311141',
  '411131',
  '211412',
  '211214',
  '211232',
  '233111',
  '211133',
  '2331112',
]

const TBL_A = [
  ' ',
  '!',
  '"',
  '#',
  '$',
  '%',
  '&',
  "'",
  '(',
  ')',
  '*',
  '+',
  ',',
  '-',
  '.',
  '/',
  '0',
  '1',
  '2',
  '3',
  '4',
  '5',
  '6',
  '7',
  '8',
  '9',
  ':',
  ';',
  '<',
  '=',
  '>',
  '?',
  '@',
  'A',
  'B',
  'C',
  'D',
  'E',
  'F',
  'G',
  'H',
  'I',
  'J',
  'K',
  'L',
  'M',
  'N',
  'O',
  'P',
  'Q',
  'R',
  'S',
  'T',
  'U',
  'V',
  'W',
  'X',
  'Y',
  'Z',
  '[',
  '\\',
  ']',
  '^',
  '_',
  'NUL',
  'SOH',
  'STX',
  'ETX',
  'EOT',
  'ENQ',
  'ACK',
  'BEL',
  'BS',
  'HT',
  'LF',
  'VT',
  'FF',
  'CR',
  'SO',
  'SI',
  'DLE',
  'DC1',
  'DC2',
  'DC3',
  'DC4',
  'NAK',
  'SYN',
  'ETB',
  'CAN',
  'EM',
  'SUB',
  'ESC',
  'FS',
  'GS',
  'RS',
  'US',
  'FNC 3',
  'FNC 2',
  'Shift B',
  'Code C',
  'Code B',
  'FNC 4',
  'FNC 1',
  'Code A',
  'Code B',
  'Code C',
  'Stop',
  'Reverse Stop',
]

const TBL_B = [
  ' ',
  '!',
  '"',
  '#',
  '$',
  '%',
  '&',
  "'",
  '(',
  ')',
  '*',
  '+',
  ',',
  '-',
  '.',
  '/',
  '0',
  '1',
  '2',
  '3',
  '4',
  '5',
  '6',
  '7',
  '8',
  '9',
  ':',
  ';',
  '<',
  '=',
  '>',
  '?',
  '@',
  'A',
  'B',
  'C',
  'D',
  'E',
  'F',
  'G',
  'H',
  'I',
  'J',
  'K',
  'L',
  'M',
  'N',
  'O',
  'P',
  'Q',
  'R',
  'S',
  'T',
  'U',
  'V',
  'W',
  'X',
  'Y',
  'Z',
  '[',
  '\\',
  ']',
  '^',
  '_',
  '`',
  'a',
  'b',
  'c',
  'd',
  'e',
  'f',
  'g',
  'h',
  'i',
  'j',
  'k',
  'l',
  'm',
  'n',
  'o',
  'p',
  'q',
  'r',
  's',
  't',
  'u',
  'v',
  'w',
  'x',
  'y',
  'z',
  '{',
  '|',
  '}',
  '~',
  'DEL',
  'FNC 3',
  'FNC 2',
  'Shift A',
  'Code C',
  'FNC 4',
  'Code A',
  'FNC 1',
  'Code A',
  'Code B',
  'Code C',
  'Stop',
  'Reverse Stop',
]

const TBL_C = [
  '00',
  '01',
  '02',
  '03',
  '04',
  '05',
  '06',
  '07',
  '08',
  '09',
  '10',
  '11',
  '12',
  '13',
  '14',
  '15',
  '16',
  '17',
  '18',
  '19',
  '20',
  '21',
  '22',
  '23',
  '24',
  '25',
  '26',
  '27',
  '28',
  '29',
  '30',
  '31',
  '32',
  '33',
  '34',
  '35',
  '36',
  '37',
  '38',
  '39',
  '40',
  '41',
  '42',
  '43',
  '44',
  '45',
  '46',
  '47',
  '48',
  '49',
  '50',
  '51',
  '52',
  '53',
  '54',
  '55',
  '56',
  '57',
  '58',
  '59',
  '60',
  '61',
  '62',
  '63',
  '64',
  '65',
  '66',
  '67',
  '68',
  '69',
  '70',
  '71',
  '72',
  '73',
  '74',
  '75',
  '76',
  '77',
  '78',
  '79',
  '80',
  '81',
  '82',
  '83',
  '84',
  '85',
  '86',
  '87',
  '88',
  '89',
  '90',
  '91',
  '92',
  '93',
  '94',
  '95',
  '96',
  '97',
  '98',
  '99',
  'Code B',
  'Code A',
  'FNC 1',
  'Code A',
  'Code B',
  'Code C',
  'Stop',
  'Reverse Stop',
]

const computeGroup = (lines: number[]): number[] => {
  const count = lines.length - 13
  const factor =
    lines.reduce((pre, item, i) => {
      if (i >= count) return pre

      return pre + item
    }, 0) /
    (Math.ceil(count / 6) * 11)

  return lines.map(item => Math.round(item / factor) || 1)
}

export function decoder(lines: number[]): string {
  const code = []
  let lookupTBL = TBL_B
  // let sumOP = 0
  let letterKey
  let letterCodePrev

  const computedLines = computeGroup(lines)

  if (!computedLines) return ''

  // extract terminal bar
  computedLines.pop()

  // skip check code and stop code using -13
  for (let i = 0; i * 6 < computedLines.length - 13; i += 1) {
    letterKey = computedLines.slice(i * 6, (i + 1) * 6).join('')
    const keyIndex = WIDTH_TBL.indexOf(letterKey)
    const letterCode = lookupTBL[keyIndex]
    // sumOP += i * keyIndex

    switch (letterCode) {
      case 'Code A':
        lookupTBL = TBL_A
        break
      case 'Code B':
        lookupTBL = TBL_B
        break
      case 'Code C':
        lookupTBL = TBL_C
        break
      case 'FNC 4':
        break
      default:
        if (letterCode) {
          if (letterCodePrev === 'FNC 4') {
            code.push(letterCode.charCodeAt(0) + 128)
          } else {
            code.push(letterCode)
          }

          letterCodePrev = letterCode
        } else {
          code.push('?')
        }
        break
    }
  }

  // letterKey = computedLines.slice(0, 6).join('')
  // if (sumOP % 103 !== WIDTH_TBL.indexOf(letterKey)) return ''

  return code.join('')
}
